package bby.app.fettool;

import bby.app.keytools.MD5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server extends Thread {
    private ServerSocket serverSocket;
    private int port=8888;
    private ExecutorService fixedThreadPool;
    private boolean isOk = false;
    MyManager myManager;
    Server(MyManager myManager){
        this.myManager=myManager;
    }
    boolean init(int post){
        this.port=post;
        try {
            if (serverSocket!=null && !serverSocket.isClosed())
                serverSocket.close();
            serverSocket = new ServerSocket(port);
//            serverSocket.setSoTimeout(10000);
            fixedThreadPool = Executors.newFixedThreadPool(5);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        isOk=true;
        return true;
    }
    private class Connect extends Thread{
        Socket socket;
        DataInputStream input;
        DataOutputStream output;
        public Connect(Socket socket){
            this.socket=socket;
        }
        private void closeScoket(){
            try {
                output.close();
            } catch (IOException e) { }
            try {
                input.close();
            } catch (IOException ioException) { }
            try {
                socket.close();
            } catch (IOException exception) { }
        }
        @Override
        public void run() {
            try {
                String userAddress=socket.getRemoteSocketAddress().toString();
                myManager.print("新发送端已连接：" + userAddress);
                //System.out.println("来自客户端的消息："+in.readUTF());

                input = new DataInputStream(socket.getInputStream());
                output = new DataOutputStream(socket.getOutputStream());
                String flag = input.readUTF();
                if ("GETKEY".equals(flag)){
                    myManager.print(userAddress+"请求公钥！");
                    output.writeUTF(myManager.receiverPage.pubKeyInput.getText());//发送公钥给用户端
                    output.flush();
                    myManager.print("已推送公钥给"+userAddress);
                    closeScoket();
                    return;//发送完公钥就结束连接
                }else if (!"SEND".equals(flag)){
                    closeScoket();
                    myManager.print("来自 "+userAddress+" 的代码错误，已主动关闭连接");
                    return;//标记为“SEND”时才开始传输文件
                }

                String filename = input.readUTF();
//                myManager.print("准备接收文件："+filename);

                String key = input.readUTF();
//                myManager.print("用公钥加密后的文件秘钥："+key);

                String md5 = input.readUTF();
//                myManager.print("文件的md5："+md5);
//                long filesize = input.readLong();//文件大小

                byte[] buffer=new byte[1024];
                if("".equals(filename)) filename="noname.txt";
                int i=1;
                if (new File(Config.RECV_DIR+filename).exists()){
                    while (new File(Config.RECV_DIR+i+'_'+filename).exists()) i++;
                    filename=""+i+'_'+filename;
                }

                OutputStream outs = new BufferedOutputStream(new FileOutputStream(Config.RECV_DIR+filename));
                int bytes=0;
                while ((bytes=input.read(buffer))==1024){
                    outs.write(buffer,0,bytes);
                    outs.flush();
                }

                if (bytes>0&&bytes<1024)
                    outs.write(buffer,0,bytes);
                outs.flush();
                outs.close();//关闭并保存文件

                myManager.print("接收完毕，验证md5中...");
                File newfile=new File(Config.RECV_DIR+filename);
                String md5_1 = MD5.getMD5(newfile);
                if (md5.equals(md5_1)){
                    output.writeUTF("OK");//告知发送端，md5验证通过
                    output.flush();
                    closeScoket();

                    RecvFile newFile= new RecvFile(filename,md5,key,userAddress,newfile.length(),new Date());
                    myManager.print("成功下载："+filename+"保存信息中...");
                    myManager.saveFile(newFile);
                    myManager.flashFileList();

                } else {//md5验证不通过，删除文件。
                    output.writeUTF("MD5_WRONG");
                    output.flush();
                    closeScoket();
                    newfile.delete();
                    myManager.print("MD5验证失败，文件可能被劫持，或者有损！");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public void run() {
        if (!isOk) return;//没准备好就不能开始
        while(true) {
            try {
                myManager.print("准备完毕，等待连接");
                System.out.println("等待连接，端口号： " + serverSocket.getLocalPort());
                Socket socket = serverSocket.accept();
                Connect connect = new Connect(socket);
                fixedThreadPool.execute(connect);//开启新线程执行连接任务
            } catch (SocketTimeoutException s) {
                System.out.println("Socket timed out!");
                break;
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
    void close(){
        try {
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

